/*
============================================================================
 Name        : dd_utf8.c
 Author      : Jian (raphyer@hotmail.com)
 Version     :
 Copyright   : GPL
 Description : dd_utf8.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_utf8.h"
#include "pd_unicode.h"


static int _ucs2_to_utf8(DD_UNICODE ucs2, DD_UTF8* utf8)
{
    if (ucs2 < 0x80) {
        if (ucs2 == 0) {
            utf8[0] = 0;
            return 0;
        } else {
            utf8[0] = ucs2;
            return 1 ;
        }
    }

    if (ucs2 >= 0x80  && ucs2 < 0x800) {
        utf8[0] = (ucs2 >> 6)   | 0xC0;
        utf8[1] = (ucs2 & 0x3F) | 0x80;
        return 2;
    }

    if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
        utf8[0] = ((ucs2 >> 12)       ) | 0xE0;
        utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
        utf8[2] = ((ucs2      ) & 0x3F) | 0x80;
        return 3;
    }
    
    return -1;
}


int _utf8_to_ucs2(const DD_UTF8* utf8, DD_UNICODE* ucs2, DD_INT left_len)
{
    if (utf8[0] < 0x80) {
        if (left_len < 1)  return -1 ;

        *ucs2 = utf8[0];
        return (utf8[0] == 0) ? 0 : 1 ;
    }

    if ((utf8[0] & 0xE0) == 0xE0) {
        if (left_len < 3)  return -1;

        *ucs2 =  (( utf8[0] & 0x0F) << 12 ) | ( (utf8[1] & 0x3F) << 6 )  | (utf8[2] & 0x3F);
        return 3;
    }

    if ((utf8[0] & 0xC0) == 0xC0) {
        if (left_len < 2)  return -1;

        *ucs2 = ((utf8[0] & 0x1F) << 6) | (utf8[1] & 0x3F);
        return 2;
    }

    return -1;
}


DD_UNICODE* dd_utf8_to_unicode(const DD_UTF8* utf8) 
{
    DD_INT i         = 0 ;
    DD_INT len       = DD_STRLEN(utf8);
    DD_INT utf8_len  = 0 ;
    DD_UNICODE* uni  = NULL ;
    DD_UNICODE* loop = NULL ;

    if (len == 0)
        return (DD_UNICODE*)DD_MALLOC(2) ;

    uni  = (DD_UNICODE*)DD_MALLOC((len + 1) * 2) ;
    loop = uni ;

    while (i < len) {

        utf8_len = _utf8_to_ucs2(utf8 + i, loop, len - i) ;

        if (utf8_len <= 0 ) 
            break ;

        i += utf8_len ;
        loop++ ;
    }

    return uni ;
}

DD_UTF8* dd_unicode_to_utf8(const DD_UNICODE* uni) 
{
    DD_INT i        = 0 ;
    DD_INT len      = 0 ;
    DD_INT utf8_len = 0 ;
    DD_UTF8* utf8   = NULL ;
    DD_UTF8* loop   = NULL ;

    __DD_CHECK_PTR(uni, DD_UNICODE, return (DD_UTF8*)DD_MALLOC(1) ) ;

    len = pd_unicode_len(uni) ;

    if (len == 0) 
        return (DD_UTF8*)DD_MALLOC(1) ;
    
    utf8 = (DD_UTF8*)DD_MALLOC((len + 1) * 3) ;
    loop = utf8 ;

    for (; i < len; i++) {

        utf8_len = _ucs2_to_utf8(*(uni + i), loop) ;

        if (utf8_len <= 0 ) 
            break ;
        
        loop += utf8_len ;
    }

    return utf8 ;
}

/* End of File */
